package com.lkd.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lkd.common.VMSystem;
import com.lkd.config.TopicConfig;
import com.lkd.contract.*;
import com.lkd.dao.VendingMachineDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.*;
import com.lkd.job.SupplyJob;
import com.lkd.service.*;
import com.lkd.utils.UUIDUtils;
import com.lkd.vo.Pager;
import com.lkd.vo.SkuVO;
import com.lkd.vo.VmVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
@Slf4j
public class VendingMachineServiceImpl extends ServiceImpl<VendingMachineDao, VendingMachineEntity> implements VendingMachineService {

    @Autowired
    private NodeService nodeService;

    @Autowired
    private VmTypeService vmTypeService;

    @Autowired
    private ChannelService channelService;


    /*
     * 分页查询
     * */
    @Override
    public Pager<VendingMachineEntity> search(Integer pageIndex, Integer pageSize, Integer status, String innerCode) {
        //1. 条件+分页查询售货机基本信息
        // 1-1 分页
        Page<VendingMachineEntity> page = new Page<>(pageIndex, pageSize);
        //1-2条件
        LambdaQueryWrapper<VendingMachineEntity> qw = new LambdaQueryWrapper<>();
        qw.eq(ObjectUtil.isNotEmpty(status), VendingMachineEntity::getVmStatus, status);
        qw.eq(StrUtil.isNotEmpty(innerCode), VendingMachineEntity::getInnerCode, innerCode);
        //1-3查询
        this.page(page, qw);
        //返回分页对象
        return Pager.build(page);
    }

    /*
     * 售货机新增
     * */
    @Transactional //事务
    @Override
    public void saveVM(VendingMachineEntity vm) {
        //1.保存售货机
        //1-1 补充基础信息
        String innerCode = UUIDUtils.getUUID();
        vm.setInnerCode(innerCode);//售货机编号
        vm.setVmStatus(VMSystem.VM_STATUS_NODEPLOY);//未投放
        //1-2 查询点位表，补充 区域 点位、合作商信息
        NodeEntity nodeEntity = nodeService.getById(vm.getNodeId());
        BeanUtil.copyProperties(nodeEntity, vm);
        //1-3 保存
        this.save(vm);
        //2.保存货道列表
        //2-1 查询售货机类型
        VmTypeEntity vmTypeEntity = vmTypeService.getById(vm.getVmType());
        //2-2 双层for循环
        ArrayList<ChannelEntity> channelList = new ArrayList<>();
        for (Integer i = 0; i < vmTypeEntity.getVmRow(); i++) {//外层行
            for (Integer j = 0; j < vmTypeEntity.getVmCol(); j++) {//内层列
                //2-3 创建活到并补充信息
                ChannelEntity channelEntity = new ChannelEntity();
                channelEntity.setChannelCode(i + "-" + j);// 1-1 2-3
                channelEntity.setVmId(vm.getId());//售货机id
                channelEntity.setInnerCode(innerCode);//售货机编号
                channelEntity.setMaxCapacity(vmTypeEntity.getChannelMaxCapacity());//货道最大容量
                channelList.add(channelEntity);

            }
        }
        //2-4 保存货道 (批量保存) insert into 表名() values (),(),(),()
        channelService.saveBatch(channelList);
    }

    @Autowired
    private RegionService regionService;

    /*
     * 根据设别编号查询vo
     * */
    @Override
    public VmVO findByInnerCode(String innerCode) {
        //1. 先查询设备
        LambdaQueryWrapper<VendingMachineEntity> qw = new LambdaQueryWrapper<VendingMachineEntity>().eq(VendingMachineEntity::getInnerCode, innerCode);
        VendingMachineEntity vm = this.getOne(qw);
        //2. 查询区域
        RegionEntity region = regionService.getById(vm.getRegionId());
        //3.查询点位
        NodeEntity node = nodeService.getById(vm.getNodeId());
        //3.封装vo
        VmVO vmVO = BeanUtil.copyProperties(vm, VmVO.class);
        vmVO.setVmId(vm.getId());
        vmVO.setRegionName(region.getName());
        vmVO.setNodeAddr(node.getAddr());
        //4.返回vo
        return vmVO;
    }

    /*
     * 更新设备状态
     * */
    @Override
    public void updateVmStatus(TaskCompleteContract taskCompleteContract) {
        //1. 取出消息内容
        int taskType = taskCompleteContract.getTaskType();
        String innerCode = taskCompleteContract.getInnerCode();

        //2.查询售货机
        LambdaQueryWrapper<VendingMachineEntity> qw = new LambdaQueryWrapper<>();
        qw.eq(VendingMachineEntity::getInnerCode, innerCode);
        VendingMachineEntity vendingMachineEntity = this.getOne(qw);

        //3.判断工单类型
        if (taskType == VMSystem.TASK_TYPE_DEPLOY) {
            vendingMachineEntity.setVmStatus(VMSystem.VM_STATUS_RUNNING);//运营中
        } else if (taskType == VMSystem.TASK_TYPE_REVOKE) {
            vendingMachineEntity.setVmStatus(VMSystem.VM_STATUS_REVOKE);//撤机
        }
        //4.更新数据库
        this.updateById(vendingMachineEntity);


    }

    // 货道补货
    @Override
    @Transactional
    public void supply(SupplyContract supplyContract) {
        //1. 取出内容
        String innerCode = supplyContract.getInnerCode();// 设备编号
        List<SupplyChannel> supplyData = supplyContract.getSupplyData();//货道详情

        //2. 根据innerCode+channelCode 查询数据库货道
        for (SupplyChannel supply : supplyData) {
            LambdaQueryWrapper<ChannelEntity> qw = new LambdaQueryWrapper<>();
            qw.eq(ChannelEntity::getInnerCode, innerCode);
            qw.eq(ChannelEntity::getChannelCode, supply.getChannelCode());
            ChannelEntity channelEntity = channelService.getOne(qw);
            //3. 原来库存量+本次补货的
            channelEntity.setCurrentCapacity(channelEntity.getCurrentCapacity() + supply.getCapacity());
            channelEntity.setLastSupplyTime(LocalDateTime.now());
            //4.更新货道数据库
            channelService.updateById(channelEntity);
        }

        //5. 更新售货机时间 update vm set last_supply_time = now() where inner_code=?
        LambdaUpdateWrapper<VendingMachineEntity> qw = new LambdaUpdateWrapper<>();
        qw.eq(VendingMachineEntity::getInnerCode, innerCode);//条件
        qw.set(VendingMachineEntity::getLastSupplyTime, LocalDateTime.now());
        this.update(qw);
    }

    @Autowired
    private SkuService skuService;

    @Autowired
    private MqttProducer producer;

    /*
     * 检查售货机是否需要补货
     * */
    @Override
    public void autoSupplyTask() {

        //1. 查询所有运营中的设备
        List<VendingMachineEntity> vmList = this.lambdaQuery()
                .eq(VendingMachineEntity::getVmStatus, VMSystem.VM_STATUS_RUNNING)
                .list();
        //2. 遍历设备查货道，找出需要补货的设备
        for (VendingMachineEntity vm : vmList) {
            // 声明发送消息对象
            SupplyContract supplyContract = new SupplyContract();
            supplyContract.setInnerCode(vm.getInnerCode());//设备编号
            ArrayList<SupplyChannel> supplyData = new ArrayList<>();
            supplyContract.setSupplyData(supplyData);//补货数据

            //2-1 查询有商品的货道
            List<ChannelEntity> channelList = channelService.lambdaQuery()
                    .eq(ChannelEntity::getInnerCode, vm.getInnerCode())
                    .gt(ChannelEntity::getSkuId, 0)
                    .list();
            // 2-2 遍历有商品的货道
            for (ChannelEntity channel : channelList) {
                // 2-3 判断货道是否需要补货
                if (channel.getMaxCapacity() - channel.getCurrentCapacity() > 0) {
                    //2-4 添加补货数据
                    SupplyChannel supplyChannel = new SupplyChannel();
                    supplyChannel.setChannelCode(channel.getChannelCode());
                    supplyChannel.setCapacity(channel.getMaxCapacity() - channel.getCurrentCapacity());
                    supplyChannel.setSkuId(channel.getSkuId());
                    SkuEntity skuEntity = skuService.getById(channel.getSkuId());
                    supplyChannel.setSkuName(skuEntity.getSkuName());
                    supplyChannel.setSkuImage(skuEntity.getSkuImage());
                    //添加到集合
                    supplyData.add(supplyChannel);
                }
            }

            //3. 发送mq异步补货消息
            if (supplyData.size() > 0) {
                try {
                    producer.send(TopicConfig.TASK_SUPPLY_TOPIC, 2, supplyContract);
                    log.info("发布补货消息成功: " + vm.getInnerCode());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("发送自动补货消息失败: " + vm.getInnerCode());
                }
            }


        }


    }

    @Override
    public void autoSupplyTask(int total, int index) {
        // 1.检查售货机是否需要补货
        List<VendingMachineEntity> vmList = this.lambdaQuery()
                .eq(VendingMachineEntity::getVmStatus,
                        VMSystem.VM_STATUS_RUNNING)
                .apply("mod(id," + total + ")=" + index).list();
        //2.遍历设备查询货道，找出需要补货的设备
        for (VendingMachineEntity vm : vmList) {
            // 声明发送消息对象
            SupplyContract supplyContract = new SupplyContract();
            supplyContract.setInnerCode(vm.getInnerCode());
            ArrayList<SupplyChannel> supplyData = new ArrayList<>();
            supplyContract.setSupplyData(supplyData); // 补货数据

            //  2-1 查询有商品的货道
            List<ChannelEntity> channelList = channelService.lambdaQuery()
                    .eq(ChannelEntity::getInnerCode, vm.getInnerCode())
                    .gt(ChannelEntity::getSkuId, 0)
                    .list();
            // 2-2 遍历有商品的货道
            for (ChannelEntity channel : channelList) {
                // 2-3 判断货道是否需要补货
                if (channel.getMaxCapacity() - channel.getCurrentCapacity() > 0) {
                    // 2-4 添加补货数据
                    SupplyChannel supplyChannel = new SupplyChannel();
                    supplyChannel.setChannelCode(channel.getChannelCode());
                    supplyChannel.setCapacity(channel.getMaxCapacity() - channel.getCurrentCapacity());
                    supplyChannel.setSkuId(channel.getSkuId());
                    SkuEntity skuEntity = skuService.getById(channel.getSkuId());
                    supplyChannel.setSkuName(skuEntity.getSkuName());
                    supplyChannel.setSkuImage(skuEntity.getSkuImage());
                    // 添加到集合
                    supplyData.add(supplyChannel);
                }
            }

            // 3.发送mq异步补货消息
            if (supplyData.size() > 0) {
                try {
                    producer.send(TopicConfig.TASK_SUPPLY_TOPIC, 2, supplyContract);
                    log.info("发布补货消息成功：" + vm.getInnerCode());
                } catch (Exception e) {
                    e.printStackTrace();
                    // throw new LogicException("发送自动补货消息失败"+vm.getInnerCode());
                    log.error("发送自动补货消息失败：" + vm.getInnerCode());
                }
            }
        }
    }

    @Override
    public List<SkuVO> getSkuListByInnerCode(String innerCode) {
        //1. 根据售货机innerCode查询货道(innerCode skuId<> 0)
        LambdaQueryWrapper<ChannelEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChannelEntity::getInnerCode, innerCode)
                .gt(ChannelEntity::getSkuId, 0);
        List<ChannelEntity> channelEntityList = channelService.list(wrapper);

        //2. 查询货道中的商品
        ArrayList<SkuVO> skuVOList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(channelEntityList)) {
            for (ChannelEntity channelEntity : channelEntityList) {
                //3. 根据货道中的skuId查询商品信息
                SkuEntity skuEntity = skuService.getById(channelEntity.getSkuId());
                //3-1 sku--SkuVo
                SkuVO skuVO = BeanUtil.copyProperties(skuEntity, SkuVO.class);
                //3-2 补齐字段
                skuVO.setCapacity(channelEntity.getCurrentCapacity());//余量
                skuVO.setImage(skuEntity.getSkuImage());//商品图片
                skuVO.setRealPrice(skuEntity.getPrice());//真实售价
                //3-3 放入集合
                skuVOList.add(skuVO);
            }
        }
        return skuVOList;
    }


    @Autowired
    private VendoutRunningService vendoutRunningService;

    // 处理出货逻辑
    @Override
    public Boolean vendout(VendoutContract vendoutContract) {
        //1. 查询售货机中有此商品库存的货道
        List<ChannelEntity> list = channelService.lambdaQuery()
                .eq(ChannelEntity::getInnerCode, vendoutContract.getInnerCode())
                .eq(ChannelEntity::getSkuId, vendoutContract.getVendoutData().getSkuId())
                .gt(ChannelEntity::getCurrentCapacity, 0)
                .list();
        if(CollUtil.isEmpty(list)){
            return false;//没库存
        }
        ChannelEntity channelEntity = list.stream().findFirst().get();
        // 2-1 扣减库存
        try {
            channelEntity.setCurrentCapacity(channelEntity.getCurrentCapacity()-1);
            channelService.updateById(channelEntity);
        }catch (Exception exception){
            exception.printStackTrace();
            log.error("出现了超卖: {}",vendoutContract.getVendoutData().getOrderNo());
            return false;
        }
        //3. 保存出货记录
        VendoutRunningEntity vendoutRunningEntity = new VendoutRunningEntity();
        vendoutRunningEntity.setOrderNo(vendoutContract.getVendoutData().getOrderNo());//订单号
        vendoutRunningEntity.setInnerCode(vendoutContract.getInnerCode());//设备号
        vendoutRunningEntity.setStatus(false); //流水是否完成
        vendoutRunningEntity.setSkuId(channelEntity.getSkuId());
        SkuEntity skuEntity = skuService.getById(channelEntity.getSkuId());
        vendoutRunningEntity.setSkuName(skuEntity.getSkuName());
        vendoutRunningEntity.setPrice(skuEntity.getPrice());
        vendoutRunningService.save(vendoutRunningEntity);

        //4. 向终端设备发送出货信息
        //4-1 封装 具体出货货道
        vendoutContract.getVendoutData().setChannelCode(channelEntity.getChannelCode());
        //4-2 发送消息
        String topic = TopicConfig.getVendoutTopic(vendoutContract.getInnerCode());
        try {
            producer.send(topic,2,vendoutContract);
            log.info("发送出货消息成功: {}",vendoutContract.getVendoutData().getOrderNo());
        }catch (Exception e){
            e.printStackTrace();
            log.error("发送出货消息失败: {}",vendoutContract.getVendoutData().getOrderNo());
        }
        //5. 出货成功
        return true;
    }

    /*
     * 售货机微服务处理出货结果
     * */
    @Override
    public Boolean vendoutResult(VendoutResultContract vendoutContract) {
       // 获取订单号
        String orderNo = vendoutContract.getVendoutData().getOrderNo();
        // 获取售货机编号
        String innerCode = vendoutContract.getInnerCode();
        // 获取货道编号
        String channelCode = vendoutContract.getVendoutData().getChannelCode();
        //判断是否出货成功
        if(vendoutContract.isSuccess()){//成功
            //更新出货流水 (需执行二次sql)
            VendoutRunningEntity vendoutRunningEntity = vendoutRunningService.lambdaQuery().eq(VendoutRunningEntity::getOrderNo, orderNo).one();
            vendoutRunningEntity.setStatus(true);
            return vendoutRunningService.updateById(vendoutRunningEntity);
        }else {//失败 货道库存+1 (仅需要执行一次sql)
            // update tb_channel set current_capacity = current_capacity+1 where inner_code= ? and channel_code = ?
            return channelService.lambdaUpdate()
                    .setSql("current_capacity=current_capacity+1")
                    .eq(ChannelEntity::getInnerCode,innerCode)
                    .eq(ChannelEntity::getChannelCode,channelCode).update();
        }


    }
}